import logging
import sys
import os
from datetime import datetime
from typing import Tuple, NoReturn, List

from integratior_service.controllers.listener.takes import Singleton
from integratior_service.controllers.common.console import Color
from integratior_service.controllers.config.logconfig import Config


if hasattr(sys, '_getframe'):
    # 0-当前frame, 1-self._get_caller_frame_info, 2-self._message_format, 3.self.debug/info/warning/error, 4. caller
    caller_frame = lambda: sys._getframe(4)
else:  # pragma: no cover
    def caller_frame():
        """Return the caller's stack frame."""
        try:
            raise Exception
        except Exception:
            return sys.exc_info()[2].tb_frame.f_back.f_back.f_back.f_back


@Singleton
class Log(object):

    def __init__(self):
        self.logger = logging.getLogger('WebUIAutoTest')
        today = datetime.now().strftime("%Y%m%d")
        ch = logging.StreamHandler()  # 控制台输出
        fh = logging.FileHandler(
            filename=(os.path.join(Config.project_dir, 'logs', 'log_' + today + '.log')),
            encoding="utf-8",
        )  # 文件输出
        # 添加Handler
        self.logger.addHandler(ch)
        self.logger.addHandler(fh)
        self.logger.setLevel(Config.logging_level)

    def _get_caller_frame_info(self) -> Tuple[str, str, int]:
        """
        :return: 代码文件路径, 函数名, 行号
        """
        f = caller_frame()
        co = f.f_code
        return co.co_filename, co.co_name, f.f_lineno

    def _message_format(self, level: str, msg: str) -> str:
        time = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
        file, func, lineno = self._get_caller_frame_info()
        lineno = str(lineno)
        file = os.path.basename(file)
        file_func_lineno = file + "-" + func + "-" + lineno
        # 格式化输出
        return "{time:<29}{level:<10}{file_func_lineno}{msg}".format(time="["+time+"]",
                                                                     level="["+level+"]",
                                                                     file_func_lineno="[ source " + file_func_lineno+"]",
                                                                     msg="[信息:"+str(msg)+"]")

    def debug(self, msg: str, *args, **kwargs) -> NoReturn:
        msg = self._message_format(level="DEBUG", msg=msg)
        Color.white_bright_foreground_black_background()
        self.logger.debug(msg, *args, **kwargs)
        Color.white_foreground_black_background()

    def info(self, msg: str, *args, **kwargs) -> NoReturn:
        msg = self._message_format(level="INFO", msg=msg)
        Color.white_foreground_black_background()
        self.logger.info(msg, *args, **kwargs)
        Color.white_foreground_black_background()

    def warning(self, msg: str, *args, **kwargs) -> NoReturn:
        msg = self._message_format(level="WARNING", msg=msg)
        Color.yellow_foreground_black_background()
        self.logger.warning(msg, *args, **kwargs)
        Color.white_foreground_black_background()

    def error(self, msg: str, *args, **kwargs) -> NoReturn:
        msg = self._message_format(level="ERROR", msg=msg)
        Color.red_foreground_black_background()
        self.logger.error(msg, *args, **kwargs)
        Color.white_foreground_black_background()

    def critical(self, msg: str, *args, **kwargs) -> NoReturn:
        msg = self._message_format(level="CRITICAL", msg=msg)
        Color.red_bright_foreground_black_background()
        self.logger.critical(msg, *args, **kwargs)
        Color.white_foreground_black_background()


def get_latest_log() -> str:
    """
        获取当前实时最新的日志文件
    :return: 文件名
    """
    log_dir = os.path.join(Config.project_dir, 'Log')
    max_mtime = 0
    max_mtime_file = ''
    for f in os.listdir(log_dir):
        if f.split('.')[-1] == 'log':
            mtime = os.path.getmtime(os.path.join(log_dir, f))
            if mtime > max_mtime:
                max_mtime = mtime
                max_mtime_file = f
    return max_mtime_file


def get_all_logs() -> List:
    """
         获取当前Log目录下所有日志文件，按照文件名日期降序排序
    """
    log_dir = os.path.join(Config.project_dir, 'Log')
    logs = filter(lambda x: x.split('.')[-1] == 'log', os.listdir(log_dir))
    return sorted(logs, reverse=True)

if __name__ == '__main__':
    logger = Log()
    logger.error("正在执行 TestCaseDemo.test_1_datadriver")